/*
 * L9Str.h
 *
 *  Created on: 2011-10-18
 *      Author: baixp
 */

#ifndef L9STR_H_
#define L9STR_H_
#include <FBase.h>
#include <FGraphics.h>
using namespace Osp::Base::Utility;
using namespace Osp::Graphics;
#include "L9Sprite.h"
#include "L9Util.h"
#include "L9Log.h"
namespace lib9bada {
class L9Str {
private:
	/**
	 *调试字符串，请将DEBUG_STRING_POS设置为true
	 * @param str String
	 */
	void Debug_Str(String str) {
		//        if (L9Config::bDebugString) {
		//            try {
		//                System.out.println("str=" + str);
		//                throw new Exception();
		//            } catch (Exception e) {
		//                e.printStackTrace();
		//            }
		//        }
	}
	//将FF00FA这种颜色字符串转换为color
	Color getColorByIntStr(String intStr, int off) {
		Color color;
		String str;
		intStr.SubString(off, 6, str);
		//颜色为ARGB格式
		unsigned int iColor=L9Util::StrToInt(str, 16);
		iColor+=((0xFF)<<24);

		color.SetRGB32(iColor);
		return color;
	}
	/**
	 * 绘制文字时的字体变量
	 */
	Font* _font;// = Font.getFont(Font.FACE_SYSTEM, 0,Font.SIZE_SMALL /*SIZE_MEDIUM*/);
	String _mapChar;
	L9Sprite* _spriteMapChar;
	int _pal;// = 0;

	//分页信息
	vector<String> _pageLines;
	int _pageLineSpace;
	int _pageLineW;
	int _nPageSize;

	void defaultInit(){
		_font=null;
		_spriteMapChar=null;
	}
public:
	L9Str();
	virtual ~L9Str();

	/**
	 * 设置图片字体参数，spriteMapChar为图片对应的sprite对象，mapChar为图片映射字符，字符的顺序对应spriteMapChar中的module
	 * @param spriteMapChar L9Sprite
	 * @param mapChar String
	 */
	void setImageFont(L9Sprite* spriteMapChar, String mapChar) {
		if(_font!=null){
			delete _font;
			_font = null;
		}
		_spriteMapChar = spriteMapChar;
		_mapChar = mapChar;
	}

	/**
	 * 使用系统字体来绘制字符串
	 * @param font Font
	 */
	void setSystemFont(Font* font) {
		if(_spriteMapChar!=null){
			delete _spriteMapChar;
			_spriteMapChar = null;
		}
		_mapChar = null;
		_font = font;
	}

	/**
	 * 获取字符的宽度
	 * @param c mchar
	 * @return int
	 */
	int getCharWidth(mchar c) {
		if (_font != null) {
			String str(c);
			Dimension dim;
			_font->GetTextExtent(str, str.GetLength(), dim);
			return dim.width;
		}
		int index =L9Util::indexOf(_mapChar,c);
		return _spriteMapChar->getModuleWidth(index);
	}

	/**
	 * 获取字符的高度
	 * @param c mchar
	 * @return int
	 */
	int getCharHeight(mchar c) {
		if (_font != null) {
			String str(c);
			Dimension dim;
			_font->GetTextExtent(str, str.GetLength(), dim);
			return dim.height;
		}
		int index = L9Util::indexOf(_mapChar,c);
		return _spriteMapChar->getModuleHeight(index);
	}

	/**
	 * 返回行字符串的高度,也就是字符串行中高度最高的字符的高度作为行的高度
	 * @param Line String
	 * @return int
	 */
	int getLineHeight(String Line) {
		int maxH = 0;
		int length = Line.GetLength();
		for (int i = 0; i < length; i++) {
			mchar c = Line[i];
			//"0x"作为颜色的标记,后面六位表示颜色值
			if (c == '0') {
				//                try {
				if (i + 1 < length) {
					mchar c2 = Line[i + 1];
					if ((c2 == 'x' || c2 == 'X')) {
						if (L9Util::isNum16(Line, i + 2, 6)) {
							i += 7; //因为i还会执行一次
							continue;
						}

					} else if ((c2 == 'p' || c2 == 'P')) {
						if (L9Util::isNum(Line, i + 2, 1)) {
							i += 2; //因为i还会执行一次
							continue;
						}

					}
				}
				//                } catch (Exception ex) {
				//                    //发生异常说明不是有效的标记
				//                    //ex.printStackTrace();
				//                }
			}
			if (maxH < getCharWidth(c)) {
				maxH = getCharWidth(c);
			}
		}
		return maxH;
	}

	/**
	 * 设置图片字体的调色板，默认使用图片本身
	 * @param pal int
	 */
	void setImagePal(int pal) {
		_pal = pal;
	}

	/**
	 * 在指定的位置绘制字符
	 * @param g Canvas*
	 * @param c mchar
	 * @param x int
	 * @param y int
	 */
	void drawChar(Canvas* g, mchar c, int x, int y) {
		if (_font != null) {
			g->DrawText(Point(x, y), String(c));
			return;
		}
		int index =L9Util::indexOf(_mapChar,c);
		_spriteMapChar->paintModule(g, index, x, y, 0, _pal);
	}

	////////////////////////////////////////////////////////有关字符串的操作/////////////////////////////////////////////////////////////////////////////
	/**
	 * 指定分割标记来分割字符串,返回风格字符串数组,支持多个分隔符连续的情况,比如：aaxxxaa ，分隔符"x"那么返回的是[aa,aa]两个字符串，二不是返回的["aa","","","","aa"]5个字符串]
	 * @param str String
	 * @param sep String
	 * @return String[]
	 */
	static vector<String> splitStr(String str, String sep) {
		vector<String> v;
		while (str.GetLength() >= sep.GetLength()) {
			str = trimStr(str, sep);
			int index = L9Util::indexOf(str,sep);
			if (index == -1) {
				if (str.GetLength() > 0) {
					v.push_back(str);
				}
				break;
			} else {
				String subStr;
				str.SubString(0, index, subStr);
				v.push_back(subStr);

				str.SubString(index + sep.GetLength(), str);
			}
		}
		return v;
	}

	/**
	 * 将字符串数组按照sep标记组合成一个字符串
	 * @param strArr String[]
	 * @param sep String
	 * @return String
	 */
	static String joinStr(vector<String> strArr, String sep) {
		String Rs = "";
		for (int i = 0; i < strArr.size(); i++) {
			Rs += strArr[i];
			if (i != strArr.size() - 1) {
				Rs += sep;
			}
		}
		return Rs;
	}

	/**
	 * 去掉字符串前边的所有sep标记
	 * @param str String
	 * @param sep String
	 * @return String
	 */
	static String leftStr(String str, String sep) {
		while (str.StartsWith(sep, 0)) {
			str.SubString(sep.GetLength(), str);
		}
		return str;
	}

	/**
	 * 去掉字符串后边的所有sep标记
	 * @param str String
	 * @param sep String
	 * @return String
	 */
	static String rightStr(String str, String sep) {
		while (str.EndsWith(sep)) {
			str.SubString(0, str.GetLength() - sep.GetLength(), str);
		}
		return str;
	}

	/**
	 * 清除字符串前后的sep标记
	 * @param str String
	 * @param sep String
	 * @return String
	 */
	static String trimStr(String str, String sep) {
		str = leftStr(str, sep);
		str = rightStr(str, sep);
		return str;
	}

	/**
	 * 用字符串sReplace替换字符串str中的sFind字符串，只替换第一个，如果要全部替换请调用replaceStrAll函数
	 * @param str String
	 * @param sFind String
	 * @param sReplace String
	 * @return String
	 */
	static String replaceStr(String str, String sFind, String sReplace) {
		int index = L9Util::indexOf(str,sFind);
		String rs = str;
		if (index != -1) {
			String tmpStr;
			str.SubString(0, index, tmpStr);
			rs = tmpStr + sReplace;
			if(index + sFind.GetLength()<str.GetLength()){//结尾的时候不要再SubString了
				str.SubString(index + sFind.GetLength(), tmpStr);
				rs += tmpStr;
			}
		}
		return rs;
	}

	/**
	 * 在字符串中查找sToken字符串，然后用sArr里面的字符串来替换，最后返回被替换后的字符串，使用如下：
	 * String str=“红队的成绩，分数XXXX,所用时间XXXX分钟!”;
	 * str=getResStr(17,"XXXX",new String[]{"86","2"});
	 * 调用getResStr函数后的字符串变为“红队的成绩，分数86,所用时间2分钟!”
	 * @param str String
	 * @param sFind String
	 * @param sReplace String
	 * @param sep String
	 * @return String
	 */
	static String replaceStr(String str, String sFind, String sReplace,
			String sep) {
		vector<String> sArr = splitStr(sReplace, sep);
		for (int i = 0; i < sArr.size(); i++) {
			str = replaceStr(str, sFind, sArr[i]);
		}
		return str;
	}

	/**
	 * 用字符串sReplace替换字符串str中的sFind字符串，全部替换个，如果只想替换第一个请调用replaceStr函数
	 * @param str String
	 * @param sFind String
	 * @param sReplace String
	 * @return String
	 */
	static String replaceStrAll(String str, String sFind, String sReplace) {
		int index = L9Util::indexOf(str,sFind);
		while (index != -1) {
			str = replaceStr(str, sFind, sReplace);
			index=L9Util::indexOf(str,sFind);
		}
		return str;
	}

	/**
	 * 将字符串分割为最大宽度为lineW的字符串数组,且将\n作为换行标识，并且支持对文字设置颜色
	 * 比如：我们的0xFF0000手机引擎0x000000是最棒的，那么“手机引擎”将会红色显示
	 * 系统字体使用0xFF0000这种格式设置颜色,图片字体这使用0p2这种方式来设置调色板
	 * @param pStr String
	 * @param lineW int
	 * @return String[]
	 */
	vector<String> updateString(String pStr, int lineW) {
		vector<String> vLines;
		if (pStr == null || pStr.GetLength() < 1) {
			return vLines;
		}

		String tmpLine;
		int width = 0;
		int max_w = lineW;
		for (int i = 0; i < pStr.GetLength();) {
			mchar c = pStr[i];
			//"0x"作为颜色的标记,后面六位表示颜色值
			if (c == '0') {
				//				try {
				if (i + 1 < pStr.GetLength()) {
					mchar c2 = pStr[i + 1];
					if (c2 == 'x' || c2 == 'X') { //0x表示系统字体的颜色
						String color;
						pStr.SubString(i + 2, 6, color);
						if (L9Util::isNum16(color, 0, color.GetLength())) {
							//int tmp = Integer.parseInt(color, 16);
							tmpLine.Append(c);
							tmpLine.Append(c2);
							tmpLine.Append(color);
							i += 7 + 1; //因为continue后没有i++了
							continue;
						}
					} else if (c2 == 'p' || c2 == 'P') { //0p表示图片字体的颜色,调色板颜色只能为[0-9]
						String color;
						pStr.SubString(i + 2, 1, color);
						if (L9Util::isNum(color, 0, color.GetLength())) {
							//String color = pStr.substring(i + 2, i + 3);
							//int tmp = Integer.parseInt(color);
							tmpLine.Append(c);
							tmpLine.Append(c2);
							tmpLine.Append(color);
							i += 2 + 1; //因为continue后没有i++了
							continue;
						}
					}
				}
				//				} catch (Exception ex) {
				//					//发生异常说明不是有效的标记
				//					//ex.printStackTrace();
				//				}
			}

			//            width += getCharWidth(c);
			int c_w=0;
			c_w=getCharWidth(c);
			if (c == '\n' || width + getCharWidth(c) > max_w) {
				if (c == '\n') {
					width = 0;
				} else {
					width = getCharWidth(c);
				}
				vLines.push_back(tmpLine);
				tmpLine = "";
			} else {
				width += getCharWidth(c);
			}
			i++;
			if (c != '\n') {
				tmpLine.Append(c);
			}
		}
		if (tmpLine.GetLength() > 0) {
			vLines.push_back(tmpLine);
			; //最后一行
		}

		return vLines;
	}

	/**
	 * 返回字符串的宽
	 * @param Line String
	 * @return int
	 */
	int getLineW(String Line) {
		int w = 0;
		for (int i = 0; i < Line.GetLength(); i++) {
			mchar c = Line[i];
			//"0x"作为颜色的标记,后面六位表示颜色值
			if (c == '0') {
				//				try {
				if (i + 1 < Line.GetLength()) {
					mchar c2 = Line[i + 1];
					if ((c2 == 'x' || c2 == 'X')) {
						String color;
						Line.SubString(i + 2, 6, color);
						if (L9Util::isNum16(color, 0, color.GetLength())) {
							//int iColor = Integer.parseInt(color, 16);
							i += 7; //因为i还会执行一次
							continue;
						}

					} else if ((c2 == 'p' || c2 == 'P')) {
						String color;
						Line.SubString(i + 2, 1, color);
						if (L9Util::isNum(color, 0, color.GetLength())) {
							//int iColor = Integer.parseInt(color);
							i += 2; //因为i还会执行一次
							continue;
						}
					}
				}
				//				} catch (Exception ex) {
				//					//发生异常说明不是有效的标记
				//					//ex.printStackTrace();
				//				}
			}
			w += getCharWidth(c);
		}
		return w;
	}

	/**
	 * 返回字符串数组中长度最宽的字符串的索引,如果Lines为空或者长度为0则返回-1
	 * @param Lines String[]
	 * @return int
	 */
	int getLineMaxWIndex(vector<String> Lines) {
		int maxW = 0;
		int index = -1;
		for (int i = 0; i < Lines.size(); i++) {
			if (maxW < getLineW(Lines[i])) {
				maxW = getLineW(Lines[i]);
				index = i;
			}
		}
		return index;
	}

	/**
	 * 返回字符串数组中最长的行宽，如果Lines为空或者长度为0则返回0
	 * @param Lines String[]
	 * @return int
	 */
	int getMaxLineW(vector<String> Lines) {
		int index = getLineMaxWIndex(Lines);
		return index != -1 ? getLineW(Lines[index]) : 0;
	}

	/**
	 * 使用循环的方式一个字符一个字符绘制字符串
	 * @param g Canvas*
	 * @param Line String
	 * @param X int
	 * @param Y int
	 */
	void drawLine(Canvas* g, String Line, int X, int Y) {
		int x = X;
		for (int i = 0; i < Line.GetLength(); i++) {
			mchar c = Line[i];
			//"0x"作为颜色的标记,后面六位表示颜色值
			if (c == '0') {
				//				try {
				if (i + 1 < Line.GetLength()) {
					mchar c2 = Line[i + 1];
					if ((c2 == 'x' || c2 == 'X')) {
						//String color = Line.substring(i + 2, i + 8);
						//int iColor = Integer.parseInt(color, 16);
						if (L9Util::isNum16(Line, i + 2, 6)) {
							Color color = getColorByIntStr(Line, i + 2);
							g->SetForegroundColor(color);
							i += 7; //因为i还会执行一次
							continue;
						}
					} else if (c2 == 'p' || c2 == 'P') { //0p表示图片字体的颜色,调色板颜色只能为[0-9]
						String color;
						Line.SubString(i + 2, 1, color);
						if (L9Util::isNum(color, 0, color.GetLength())) {
							int iColor = L9Util::StrToInt(color, 10);
							setImagePal(iColor);
							i += 2; //因为i还会执行一次
							continue;
						}
					}
				}
				//				} catch (Exception ex) {
				//					//发生异常说明不是有效的标记
				//					//ex.printStackTrace();
				//				}
			}

			drawChar(g, c, x, Y);
			x += getCharWidth(c);
		}
		Debug_Str(Line);
	}

	/**
	 * 设置分页绘制字符串信息,pageLineW表示页面的宽度，pageH表示页面的高度,lineSpace表示行间距
	 * @param sText String
	 * @param pageLineW int
	 * @param pageH int
	 * @param lineSpace int
	 */
	void setPageSize(String sText, int pageLineW, int pageH, int lineSpace) {
		_pageLines = updateString(sText, pageLineW);
		_pageLineW = pageLineW;
		_pageLineSpace = lineSpace;
		_nPageSize = pageH / (getLineHeight(_pageLines[0]) + lineSpace);
	}

	/**
	 * 返回每页的行数
	 * @return int
	 */
	int getPageSize() {
		return _nPageSize;
	}

	/**
	 * 字符串分页后，返回有多少页
	 * @return int
	 */
	int getPageCount() {
		int nPages = _pageLines.size() / _nPageSize;
		if (nPages * _nPageSize != _pageLines.size()) {
			nPages++;
		}
		return nPages;
	}

	/**
	 * 绘制指定页的字符串,调用drawPage之前会先调用setPageSize来设置分页信息
	 * @param g Canvas*
	 * @param iPage int
	 * @param x int
	 * @param y int
	 */
	void drawPage(Canvas* g, int iPage, int x, int y) {
		int off = iPage * _nPageSize;
		int YY = y;
		for (int i = off; i < off + _nPageSize && i< _pageLines.size(); i++) {
			drawLine(g, _pageLines[i], x, YY);
			YY += getLineHeight(_pageLines[i]) + _pageLineSpace;
		}
	}

	/**
	 * 绘制字符串的对齐方式，左对齐
	 */
	static const int K_Line_Align_Left = 0;
	/**
	 * 绘制字符串的对齐方式，居中对齐
	 */
	static const int K_Line_Align_Center = 1;
	/**
	 * 绘制字符串的对齐方式，右对齐
	 */
	static const int K_Line_Align_Right = 2;
	/**
	 * 在给定的位置及宽度的限制下绘制行字符串,align为绘制行的对齐方式，0表示左对齐,1表示居中对齐,2表示右对齐
	 * @param g Canvas*
	 * @param line String
	 * @param y int
	 */
	void drawLine(Canvas* g, String line, int x, int y, int lineW, int align) {
		switch (align) {
		case K_Line_Align_Left:
			drawLine(g, line, x, y);
			break;
		case K_Line_Align_Center: {
			int sW = getLineW(line);
			int XX = x + ((lineW - sW) >> 1);
			drawLine(g, line, XX, y);
		}
			break;
		case K_Line_Align_Right: {
			int sW = getLineW(line);
			int XX = x + lineW - sW;
			drawLine(g, line, XX, y);
		}
			break;
		}
	}

	/**
	 * 在给定的位置及宽度的限制下绘制页,调用drawPage之前会先调用setPageSize来设置分页信息,align为绘制行的对齐方式，0表示左对齐,1表示居中对齐,2表示右对齐
	 * @param g Canvas*
	 * @param iPage int
	 * @param x int
	 * @param y int
	 * @param align int
	 */
	void drawPage(Canvas* g, int iPage, int x, int y, int align) {
		int off = iPage * _nPageSize;
		int YY = y;
		for (int i = off; i < off + _nPageSize && i< _pageLines.size(); i++) {
			drawLine(g, _pageLines[i], x, YY, _pageLineW, align);
			YY += getLineHeight(_pageLines[i]) + _pageLineSpace;
		}
	}
};
};

#endif /* L9STR_H_ */
